﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Outlook = Microsoft.WindowsMobile.PocketOutlook;
using System.Collections.ObjectModel;

namespace GSync
{

    public abstract class OutlookMobileDataProvider<T, C>: IDataProvider 
        where T: Microsoft.WindowsMobile.PocketOutlook.PimItem
        where C: Outlook.PimItemCollection
    { 
        protected Microsoft.WindowsMobile.PocketOutlook.OutlookSession _Session;
        protected Microsoft.WindowsMobile.PocketOutlook.OutlookSession Session
        {
            get
            {
                if (_Session == null)
                {
                    _Session = new Outlook.OutlookSession();
                }
                return _Session;
            }
        }

        protected abstract C ItemCollection
        {
            get;
        }

        #region IDataProvider Members

        public virtual ReadOnlyCollection<InternalEntry> AllRecords
        {
            get
            {
                List<InternalEntry> allEntries = (from T nativeEntry
                                                   in ItemCollection
                                                   select ConvertToInternal(nativeEntry)).ToList();

                allEntries.RemoveAll(c => c == null);

                return allEntries.AsReadOnly();
            }
        }

        public abstract void AddEntry(InternalEntry entry);

        public virtual void UpdateEntry(InternalEntry entry)
        {
            T targerNativeEntry = null;
            if (entry.ID != null)
                targerNativeEntry = this.FindNativeEntryByIDOrDefault(entry.ID);

            if (targerNativeEntry == null)
                targerNativeEntry = entry.InternalObject as T;

            if (targerNativeEntry == null)
            {
                AddEntry(entry);
            }
            else
            {
                CopyToNative(entry, targerNativeEntry);
                targerNativeEntry.Update();
            }

            
        }

        public abstract void DeleteEntry(InternalEntry entry);

        public virtual bool CanModifyEntryID
        {
            get { return true; }
        }

        #endregion


        #region protected properties
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        protected T FindNativeEntryByID(string id)
        {
            T result = FindNativeEntryByIDOrDefault(id);

            if (result == null)
            {
                throw new ArgumentException(string.Format("Native record with ID='{0}' wasn't found.", id));
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        protected T FindNativeEntryByIDOrDefault(string id)
        {
            T result = null;

            foreach (T nativeEntry in ItemCollection)
            {
                if (nativeEntry.Properties["_ID"] != null && id.Equals(nativeEntry.Properties["_ID"] as string))
                {
                    result = nativeEntry;
                   
                }
            }

            return result;
        }

        #endregion


        #region IDisposable Members

        public void Dispose()
        {
            if (_Session != null)
                _Session.Dispose();

        }

        #endregion    



        protected abstract InternalEntry ConvertToInternal(T nativeEntry);

        protected abstract void CopyToNative(InternalEntry entry, T nativeEntry);



    }

}
